package com.itbaizhan;

import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.apache.commons.io.FileUtils;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/*非对称加密
* 公钥加密，用私钥解密
* 私钥加密，公钥解密*/
public class RSAdemo {
    public static void main(String[] args) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchPaddingException {
        //1,原文
        String input = "itbaizhan";

        //密文
        String input2 = "UmDy0/HY0CawkqGOOZRosTbI+EdSbkQvQOnk6cGkFJV5EynryNGgG9D21yTeaxlNRP1pwLrgRT83Kpie/kaE5pSu75MLrXqESNdXV5rj4n8ljQ6SHltqmQKTCYiRY8pY+t/gxukahMoVLGi+Mn4SfmmSANywS5KUKgbDi3ZwOuYmEA/tMaCdfULqFVUiPuzwQy2u9juTDUuTLASvBOK8hWW5NnyoIKjlx2BIvwPi7LMaRTUCFauyduhcoZyVPurpxifHfxDSRX8oa1WY2DDAj81fOimWEESH82NobOUC/RcE1DwrBkEZdVYTaWPSiWw0IMT8AUQUafkun8mEFeDn/A==";
        //2,加密算法
        String algorithm = "RSA";

        //3，生成密钥文件  ，不写存放在哪个硬盘，会存放在根目录
        //generateKey(algorithm,"a.pub","a.pri");

        //4.获取公钥
       // PublicKey publicKey = getPublicKey("a.pub",algorithm);
        //5加密
       // String s = encryptRSA(input,publicKey,algorithm);
      //  System.out.println(s);//UmDy0/HY0CawkqGOOZRosTbI+EdSbkQvQOnk6cGkFJV5EynryNGgG9D21yTeaxlNRP1pwLrgRT83Kpie/kaE5pSu75MLrXqESNdXV5rj4n8ljQ6SHltqmQKTCYiRY8pY+t/gxukahMoVLGi+Mn4SfmmSANywS5KUKgbDi3ZwOuYmEA/tMaCdfULqFVUiPuzwQy2u9juTDUuTLASvBOK8hWW5NnyoIKjlx2BIvwPi7LMaRTUCFauyduhcoZyVPurpxifHfxDSRX8oa1WY2DDAj81fOimWEESH82NobOUC/RcE1DwrBkEZdVYTaWPSiWw0IMT8AUQUafkun8mEFeDn/A==


        //解密
        //1获取私钥
        PrivateKey privateKey = getPrivateKey("a.pri", algorithm);
        //解密
        String s = decryptRSA(input2, privateKey, algorithm);
        System.out.println(s);
    }


    /**
     * 生成密钥
     * @param algorithm  算法
     *
     * @param pubPath   公钥保存路径
     * @param priPath    私钥保存路径
     */

    public static  void generateKey(String algorithm,String pubPath,String priPath) throws NoSuchAlgorithmException, IOException {
        //1,获取密钥生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        //2获取密钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        //3获取公钥
        PublicKey publicKey = keyPair.getPublic();
        //4，获取私钥
        PrivateKey privateKey = keyPair.getPrivate();
        //5获取byte数组
        byte[] publicKeyEncoded = publicKey.getEncoded();
        byte[] privateKeyEncoded = privateKey.getEncoded();
        //6,编译为base64编码
        //com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
        String publicKeyString = Base64.encode(publicKeyEncoded);
        String privateKeyString = Base64.encode(privateKeyEncoded);
        //7，保存文件  要用这 commons-io 依赖
        FileUtils.writeStringToFile(new File(pubPath),publicKeyString, Charset.forName("UTF-8"));
        FileUtils.writeStringToFile(new File(priPath),privateKeyString, Charset.forName("UTF-8"));


    }


    /**
     * 读取公钥
     * @param publicPath
     * @param algorithm
     * @return
     */
    public static PublicKey getPublicKey(String publicPath,String algorithm) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {

        //1,读取文件
        String s = FileUtils.readFileToString(new File(publicPath), Charset.forName("UTF-8"));
        //2,获取密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        //构建公密钥规范
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decode(s));

        return keyFactory.generatePublic(x509EncodedKeySpec);

    }

    /*读取私钥
    * 将读取到的文件放进密钥规范，再用密钥工厂读取*/

    /**
     *
     * @param privatePath  私钥路径
     * @param algorithm    算法
     * @return
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static PrivateKey getPrivateKey(String privatePath,String algorithm) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
        //1,读取文件
        String s = FileUtils.readFileToString(new File(privatePath), Charset.forName("UTF-8"));
        //2 获取密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);

        //构建密钥规范   与公钥的不同
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decode(s));
        return keyFactory.generatePrivate(keySpec);


    }

    /**
     *加密
     * @param input  原文
     * @param key   密钥
     * @param algorithm  算法
     * @return
     */
     public static String encryptRSA(String input,Key key,String algorithm) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        //1 创建加密对象
         Cipher cipher = Cipher.getInstance(algorithm);
         //2,初始化加密
         cipher.init(Cipher.ENCRYPT_MODE,key);
         //3,公钥加密
         byte[] bytes = cipher.doFinal(input.getBytes());
         return Base64.encode(bytes);  //转为base64编码

     }

    /**
     * 解密
     * @param input   密文
     * @param key   密钥
     * @param algorithm   算法

     */
    public static String decryptRSA(String input,Key key,String algorithm) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        //1 创建加密对象
        Cipher cipher = Cipher.getInstance(algorithm);
        //2,初始化加密
        cipher.init(Cipher.DECRYPT_MODE,key);
        //3,密文经过Base64编码 ，所以先转为字节数组
        byte[] decode = Base64.decode(input);
        //4,对密文解密
        byte[] bytes = cipher.doFinal(decode);

        return new String(bytes);

    }

}
/*非对称加密
非对称加密指的是：加密和解密使用不同的秘钥，一把作为公开的公钥，另一把作为私钥。公钥加密的信息，只有私钥才能解密。私钥加密的信息，只有公钥才能解密。

非对称加密算法
RSA
ECC
特点
加密和解密使用不同的密钥
如果使用私钥加密, 只能使用公钥解密
如果使用公钥加密, 只能使用私钥解密
处理数据的速度较慢, 因为安全级别高*/